<?php

use IYUU\sdk\CoolQ\Domain\Message as DomainMessage;
use Yaf\Dispatcher;
use Yaf\Exception;
use IYUU\sdk\CoolQ\BotResponse;
use IYUU\sdk\CoolQ\OneBotApi;
use IYUU\sdk\CoolQ\Message;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

/**
 * 机器人
 * Class BotController
 */
class BotController extends BaseController
{
    /**
     * 默认初始化方法，如果不需要，可以删除掉这个方法
     * 如果这个方法被定义，那么在Controller被构造以后，Yaf会调用这个方法
     */
    public function init()
    {
        $this->createMemberRegistry();
        // 关闭自动渲染模板
        Dispatcher::getInstance()->disableView();
    }

    /**
     * 机器人默认动作
     * - /usr/local/bin/go-cqhttp -d -c /www/wwwroot/runtime/go-cqhttp/config.yml
     * @param string|int $qq
     * @return bool
     * @throws Exception
     */
    public function indexAction($qq = 'qq'): bool
    {
        $bot = new BotResponse($this->getResponse());
        $bot->init($qq)->response()->output();

        return false;
    }

    /**
     * 显示规则关键字列表
     *
     * @param string|int $page
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function keywordAction(int $page = 1): bool
    {
        if (empty($page)) {
            $page = 1;
        } else {
            if (is_numeric($page)) {
                $page = abs((int)$page);
            } else {
                $page = 1;
            }
        }
        $rule = RuleKeywordModel::where('module', '=', 'basic')->page($page, 20)->select();
        if ($rule->isEmpty()) {
            echo '暂无规则';
        }
        $data = [];
        /**
         * @var int $index
         * @var RuleModel $item
         */
        foreach ($rule as $item) {
            $data[] = sprintf('%d、%s（%s）%s', $item->id, $item->content, 0 === $item->status ? 'OFF' : 'ON', $item->match_type_text);
        }
        p_pre($rule->toArray());

        return false;
    }

    /**
     * 发送消息（二次封装）
     * - 签名算法：$hash = md5($token . $message_type . $id . $message . $time . $token);
     *
     * @return bool
     */
    public function sendAction():bool
    {
        // 1. 载入配置
        $config = include BotResponse::getConfigPath();
        $config = $config['qq'];

        // 2. 接收参数（id, message, time, sign, message_type）
        $req = $this->getRequest();
        $message_type = strval($req->getPost('message_type', 'group'));
        $id = (int)$req->getPost('id', 0);
        $message = strval($req->getPost('message', ''));
        $time = intval($req->getPost('time', 0));
        $sign = strval($req->getPost('sign', ''));
        if (empty($id) || empty($message) || empty($time) || empty($sign) || !in_array($message_type, ['private', 'group'])) {
            return $this->json($req->getPost(), 401, '参数不能为空');
        }

        // 3. 检查发送开关
        if (empty($config['enabled'][$message_type])) {
            return $this->json([], 202, $message_type. '发送开关已关闭');
        }

        // 4. 验证时间戳
        $absTime = abs(time() - $time);
        if ($absTime > 15) {
            return $this->json([], 402, '错误的时间戳：误差超过15秒');
        }

        // 5. 验证签名
        $token = $config['token'];
        $hash = md5($token . $message_type . $id . $message . $time . $token);
        if ($hash !== $sign) {
            return $this->json($req->getPost(), 403, '错误的签名');
        }

        // 6. 发送消息
        $cq = new OneBotApi($config['host'], $config['token']);
        if (intval($req->getPost('sync', 1))) {
            // 异步发送
            $cq->enqueue(new Message($message, $id, $message_type === 'group', false));
        } else {
            // 同步发送
            $cq->sendMsg($message_type, $id, $message);
        }

        return $this->json(['success' => true]);
    }

    /**
     * 清理Bot产生的缓存
     * @return bool
     */
    public function clearAction():bool
    {
        // 限定CLI模式执行
        if (PHP_SAPI !== 'cli') {
            exit("You must run the CLI environment\n");
        }
        $config = include BotResponse::getConfigPath();
        $config = $config['qq'];
        // 1. 清理缓存文件
        $cache_map = ['cache' ,'images' , 'videos', 'voices'];
        $base_dir = $config['oneBot_dir'] ?? runtime_path() . DIRECTORY_SEPARATOR . ini_get('yaf.environ') . '/go-cqhttp/data/';
        array_walk($cache_map, function ($path, $k) use ($base_dir) {
            $dir = $base_dir . $path;
            if (clearDir($dir)) {
                //Logger::info('清理成功！目录 ' . $dir);
            } else {
                Logger::info('失败啦！可能无权限或目录不存在 ' . $dir);
            }
        });

        // 2. 清理数据表
        DomainMessage::clear();

        return false;
    }

    /**
     * 测试动作
     * Yaf支持直接把\Yaf\Request_Abstract::getParam()得到的同名参数作为Action的形参
     *
     * @param string $name
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function testAction(string $name = 'IYUU'): bool
    {
        // 重置字节码缓存的内容
        function_exists('opcache_reset') and opcache_reset();
        // 1. 测试数据库读取
        $rs = ModulesModel::find(1);
        p_pre($rs->toArray());

        return false;
    }

    /**
     * 通知接口
     */
    public function notifyAction(): bool
    {
        try {
            echo 'ok';
            Logger::log('queue_notify', p($_REQUEST));
        } catch (\Throwable $exception) {
        }
        return false;
    }
}
